/*
	Copyright (C) 1994 Sean Luke

	COWSArrayLibrary.m
	Version 1.0
	Sean Luke
*/


#import "COWSArrayLibrary.h"
#import "COWSArrayNode.h"
#import <stdio.h>

@implementation COWSArrayLibrary

- init
	{
	id returnval=[super init];
	hashtable=[[HashTable alloc] initKeyDesc:"*"valueDesc:"@"];
	counter=0;
	return returnval;
	}


- free
	{
	[hashtable freeObjects];
	[hashtable empty];
	[hashtable free];
	return [super free];	
	}
	

- loadLibrary:sender
	{
	[sender addLibraryFunction:"make-array"
			selector:@selector(array_makearray:)
			target:self];
	[sender addLibraryFunction:"free-array"
			selector:@selector(array_freearray:)
			target:self];
	[sender addLibraryFunction:"set-array"
			selector:@selector(array_setarray:)
			target:self];
	[sender addLibraryFunction:"array"
			selector:@selector(array_getarray:)
			target:self];
	[sender addLibraryFunction:"array?"
			selector:@selector(array_getarray:)
			target:self];
	
	// clear out objects
	[hashtable freeObjects];
	[hashtable empty];
	return self;
	}

	


- array_makearray:arg_list
	{
	id return_val=[[COWSStringNode alloc] init];
	int limits[COWSMAXARRAYLIMITS];
	int x=0;
	char key[255]; /*some big number */
	id current;
	
	while ([arg_list top]!=NULL)
		{
		if (x==COWSMAXARRAYLIMITS)		// too many limits already
			{
			[return_val setString:"make-array error:  too many array limits"];
			[return_val setError:YES];
			return return_val;
			}
		current=[arg_list pop];
		limits[x]=(int) atof([current string]);
		[current free];
		x++;
		}
	
	current=[[COWSArrayNode alloc] initTable:(const int*) limits:x];
	if (current==NULL)
		{
		[return_val setString:"make-array error:  weird array limits"];
		[return_val setError:YES];
		return return_val;
		}
	
	sprintf(key,"array %d",counter);
	[hashtable insertKey:newstr(key) value:current];
	counter++;

	[return_val setString:key];
	return return_val;
	}


- array_freearray:arg_list		// removes by first item no matter what
	{
	id return_val=[[COWSStringNode alloc] init];
	if ([arg_list top]!=NULL)
		{
		id current=[arg_list pop];
		[hashtable removeKey: (const void*) [current string]];
		[current free];
		[return_val setString:"t"];
		return return_val;
		}
	[return_val setString:"free-array error:  nothing to free"];
	[return_val setError:YES];
	return return_val;
	}


- array_setarray:arg_list
	{
	id return_val=[[COWSStringNode alloc] init];
	id array;
	id value;
	id answer;
	int coords[COWSMAXARRAYLIMITS];
	int x=0;

	if ([arg_list top]!=NULL)		// no array name
		{
		id current=[arg_list pop];
		array=[hashtable valueForKey:(const void*)[current string]];
		[current free];
		if (array==nil)
			{
			[return_val setString:"set-array error:  no such array"];
			[return_val setError:YES];
			return return_val;
			}
		}
	else
		{
		[return_val setString:"set-array error:  no array to set"];
		[return_val setError:YES];
		return return_val;
		}
		
	if ([arg_list top]!=NULL)		// no value to set
		{
		value=[arg_list pop];
		}
	else
		{
		[return_val setString:"set-array error:  no value to set"];
		[return_val setError:YES];
		return return_val;
		}
		
	while ([arg_list top]!=NULL)
		{
		id current;
		if (x==COWSMAXARRAYLIMITS)		// too many limits already
			{
			[return_val setString:
				"set-array error:  too many coordinates"];
			[return_val setError:YES];
			return return_val;
			}
		current=[arg_list pop];
		coords[x]=(int) atof([current string]);
		[current free];
		x++;
		}

	answer=[array setValue:(const int*) coords:[value string]];

	[return_val setString:[value string]];
	[value free];
	
	if (answer==NULL)
		{
		[return_val setString:"set-array error:  weird coordinates"];
		[return_val setError:YES];
		return return_val;
		}
		
	return return_val;
	}


- array_getarray:arg_list
	{
	id return_val=[[COWSStringNode alloc] init];
	id array;
	const char* answer;
	int coords[COWSMAXARRAYLIMITS];
	int x=0;

	if ([arg_list top]!=NULL)		// no array name
		{
		id current=[arg_list pop];
		array=[hashtable valueForKey:(const void*)[current string]];
		[current free];
		if (array==nil)
			{
			[return_val setString:"array error:  no such array"];
			[return_val setError:YES];
			return return_val;
			}
		}
	else
		{
		[return_val setString:"array error:  no array to set"];
		[return_val setError:YES];
		return return_val;
		}
		
	while ([arg_list top]!=NULL)
		{
		id current;	
		if (x==COWSMAXARRAYLIMITS)		// too many limits already
			{
			[return_val setString:"array error:  too many coordinates"];
			[return_val setError:YES];
			return return_val;
			}
		current=[arg_list pop];
		coords[x]=(int) atof([current string]);
		[current free];
		x++;
		}

	answer=[array value:(const int*) coords];

	if (answer==NULL)
		{
		[return_val setString:"array error:  weird coordinates"];
		[return_val setError:YES];
		return return_val;
		}
		
	[return_val setString:answer];
	return return_val;
	}


- array_isarray:arg_list
	{
	id return_val=[[COWSStringNode alloc] init];
	id array;

	if ([arg_list top]!=NULL)		// no array name
		{
		id current=[arg_list pop];
		array=[hashtable valueForKey:(const void*)[current string]];
		[current free];
		if (array==nil)
			{
			[return_val setString:"f"];
			}
		else [return_val setString:"t"];
		}
	else
		{
		[return_val setString:"array error:  no array to set"];
		[return_val setError:YES];
		return return_val;
		}
	return return_val;
	}


- pauseCancelled:sender
	{
	return self;
	}
@end